package cn.swenty.backstage.sso.server.web;

import java.net.URI;
import java.net.URISyntaxException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.oltu.oauth2.as.issuer.MD5Generator;
import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
import org.apache.oltu.oauth2.as.issuer.OAuthIssuerImpl;
import org.apache.oltu.oauth2.as.response.OAuthASResponse;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.error.OAuthError;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.apache.oltu.oauth2.common.message.types.ParameterStyle;
import org.apache.oltu.oauth2.common.utils.OAuthUtils;
import org.apache.oltu.oauth2.rs.request.OAuthAccessResourceRequest;
import org.apache.oltu.oauth2.rs.response.OAuthRSResponse;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import cn.swenty.backstage.sso.server.core.commons.Constants;
import cn.swenty.backstage.sso.server.service.OAuthService;
import zy.mp.backstage.framework.common.util.StringUtil;

/**
 * @ClassName: OAtuth2Controller
 * @Description: TODO(OA授权)
 * @author sunyang
 * @date 2018年1月26日 上午10:23:33
 * 	
 */
@Controller
public class OAuth2Controller {

	private static Logger logger = LoggerFactory.getLogger(OAuth2Controller.class);

	@Autowired
	private OAuthService oAuthService;

	@RequestMapping("/oauth2/accessToken")
	public HttpEntity<String> token(HttpServletRequest request) throws URISyntaxException, OAuthSystemException {

			String authCode = request.getParameter(OAuth.OAUTH_CODE);
			logger.debug("get oauth code");

			// 生成Access Token
			OAuthIssuer oauthIssuerImpl = new OAuthIssuerImpl(new MD5Generator());
			final String accessToken = oauthIssuerImpl.accessToken();
			oAuthService.addAccessToken(accessToken, oAuthService.getUsernameByAuthCode(authCode));

			// 生成OAuth响应
			OAuthResponse response = OAuthASResponse.tokenResponse(HttpServletResponse.SC_OK)
													.setAccessToken(accessToken)
													.setExpiresIn(String.valueOf(oAuthService.getExpireIn()))
													.buildJSONMessage();

			// 根据OAuthResponse生成ResponseEntity
			return new ResponseEntity<String>(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));

	}
	
	
	   @RequestMapping("authorize")
	   public Object authorize(HttpServletRequest request) throws URISyntaxException, OAuthSystemException {

	        try {
	            Subject subject = SecurityUtils.getSubject();
	            //如果用户没有登录，跳转到登陆页面
	            if(!subject.isAuthenticated()) {
	            	return "login";
	            }

	            String username = (String)subject.getPrincipal();
	            
	            OAuthIssuerImpl oauthIssuerImpl = new OAuthIssuerImpl(new MD5Generator());
	            //生成授权码
	            String authorizationCode = oauthIssuerImpl.authorizationCode();
	            
	            logger.debug("create authorization code '"+authorizationCode+"'");
	            
	            //放到缓存中
                oAuthService.addAuthCode(authorizationCode, username);
                
	            //进行OAuth响应构建
	            OAuthASResponse.OAuthAuthorizationResponseBuilder builder =
	            					OAuthASResponse.authorizationResponse(request, HttpServletResponse.SC_FOUND)
	            					 //设置授权码
	            					.setCode(authorizationCode);
	           
	            //得到到客户端重定向地址
	            String redirectURI = request.getParameter(OAuth.OAUTH_REDIRECT_URI);
	            if(StringUtil.isNull(redirectURI)){
	            	throw OAuthProblemException.error("invalid_request", "Missing parameters: redirectUri");
	            }

	            //构建响应
	            final OAuthResponse response = builder.location(redirectURI).buildQueryMessage();

	            //根据OAuthResponse返回ResponseEntity响应
	            HttpHeaders headers = new HttpHeaders();
	            headers.setLocation(new URI(response.getLocationUri()));
	            return new ResponseEntity<String>(headers, HttpStatus.valueOf(response.getResponseStatus()));
	        } catch (OAuthProblemException e) {
	        	
	        	logger.error("error "+e);
	            //出错处理
	            String redirectUri = e.getRedirectUri();
	            if (OAuthUtils.isEmpty(redirectUri)) {
	            	
	            	OAuthResponse res = OAuthASResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
													   .setError("OAuth callback url needs to be provided by client!!!")
													   .buildJSONMessage();
	                //告诉客户端没有传入redirectUri直接报错
	                return new ResponseEntity<String>(res.getBody(), HttpStatus.NOT_FOUND);
	            }

	            //返回错误消息（如?error=）
	            final OAuthResponse response = OAuthASResponse.errorResponse(HttpServletResponse.SC_FOUND)
	            											  .error(e)
	            											  .location(redirectUri)
	            											  .buildQueryMessage();
	            HttpHeaders headers = new HttpHeaders();
	            headers.setLocation(new URI(response.getLocationUri()));
	            return new ResponseEntity<String>(headers, HttpStatus.valueOf(response.getResponseStatus()));
	        }
	    }

	   @RequestMapping("/oauth2/userInfo")
	    public HttpEntity<String> userInfo(HttpServletRequest request) throws OAuthSystemException {
	        try {

	            //构建OAuth资源请求
	            OAuthAccessResourceRequest oauthRequest = new OAuthAccessResourceRequest(request, ParameterStyle.QUERY);
	            //获取Access Token
	            String accessToken = oauthRequest.getAccessToken();
	            //验证Access Token
	            if (!oAuthService.checkAccessToken(accessToken)) {
	                // 如果不存在/过期了，返回未验证错误，需重新验证
	                OAuthResponse oauthResponse = OAuthRSResponse.errorResponse(HttpServletResponse.SC_UNAUTHORIZED)
	                											 .setRealm(Constants.RESOURCE_SERVER_NAME)
	                											 .setError(OAuthError.ResourceResponse.INVALID_TOKEN)
	                											 .buildHeaderMessage();
	                HttpHeaders headers = new HttpHeaders();
	                headers.add(OAuth.HeaderType.WWW_AUTHENTICATE, oauthResponse.getHeader(OAuth.HeaderType.WWW_AUTHENTICATE));
	                return new ResponseEntity<String>(headers, HttpStatus.UNAUTHORIZED);
	            }
	            //返回用户名
	            String username = oAuthService.getUsernameByAccessToken(accessToken);
	            SecurityUtils.getSubject().logout();
	            return new ResponseEntity<String>(username, HttpStatus.OK);
	        } catch (OAuthProblemException e) {
	        	
	        	logger.error("error "+e);
	        	//判断是否有错误信息
	            if (OAuthUtils.isEmpty(e.getError())) {
	                OAuthResponse oauthResponse = OAuthRSResponse
										                        .errorResponse(HttpServletResponse.SC_UNAUTHORIZED)
										                        .setRealm(Constants.RESOURCE_SERVER_NAME)
										                        .buildHeaderMessage();

	                HttpHeaders headers = new HttpHeaders();
	                headers.add(OAuth.HeaderType.WWW_AUTHENTICATE, oauthResponse.getHeader(OAuth.HeaderType.WWW_AUTHENTICATE));
	                return new ResponseEntity<String>(headers, HttpStatus.UNAUTHORIZED);
	            }else{
	            	  OAuthResponse oauthResponse = OAuthRSResponse
			                    .errorResponse(HttpServletResponse.SC_UNAUTHORIZED)
			                    .setRealm(Constants.RESOURCE_SERVER_NAME)
			                    .setError(e.getError())
			                    .setErrorDescription(e.getDescription())
			                    .setErrorUri(e.getUri())
			                    .buildHeaderMessage();

	            	  HttpHeaders headers = new HttpHeaders();
	            	  headers.add(OAuth.HeaderType.WWW_AUTHENTICATE, oauthResponse.getHeader(OAuth.HeaderType.WWW_AUTHENTICATE));
	            	  return new ResponseEntity<String>(HttpStatus.BAD_REQUEST);
	            }
	        }
	    }

}
